package com.mf.ergate.web.controller;

import com.mf.ergate.web.common.exception.BusinessException;
import com.mf.ergate.web.security.LoginContext;
import feign.FeignException;
import feign.RetryableException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * Web端异常处理类
 * User: zhaoming
 * Date: 2017-08-24
 * To change this template use File | Settings | File Templates.
 */
@ControllerAdvice
public class ExceptionHandlerController {

	//日志
	public Logger logger = LoggerFactory.getLogger(getClass());

	//500错误页面
	private static final String INTERNAL_SERVER_ERROR_ERROR_VIEW = "common/error/private_error_500";
	//504错误页面
	private static final String TIME_OUT_VIEW = "common/error/private_error_500";
	//400错误页面
	private static final String INVALID_REQUEST_ERROR_VIEW = "common/error/private_error_500";
	//401错误页面
	private static final String UNAUTHORIZED_ERROR_VIEW = "common/error/private_error_500";
	//403错误页面
	private static final String FORBIDDEN_ERROR_VIEW = "common/error/private_error_500";
	//404错误页面
	private static final String NOT_FOUND_ERROR_VIEW = "common/error/private_error_404";

	/**
	 * 自定义业务异常处理
	 */
	@ExceptionHandler(value = BusinessException.class)
	public ModelAndView businessErrorHandler(HttpServletRequest request, HttpServletResponse response, BusinessException e) throws Exception {

		String errorMessage = "用户["+ LoginContext.getLoginUser().getUserNo()+"]: " + e.getMessage();
		logger.error(errorMessage, e);

		// 是否AJAX提交
		boolean isAjax = this.isAjax(request);
		if (isAjax) {
			// 如果是ajax提交，则返回异常
			response.setContentType("text/xml;charset=UTF-8");
			PrintWriter writer = response.getWriter();
			writer.write(e.getMessage());
			writer.flush();
			return null;
		} else {
			// 如果不是ajax提交，则显示默认出错页面
			ModelAndView modelAndView = new ModelAndView(INTERNAL_SERVER_ERROR_ERROR_VIEW);
			if(HttpServletResponse.SC_INTERNAL_SERVER_ERROR == e.getStatusCode()){
				modelAndView.setViewName(INTERNAL_SERVER_ERROR_ERROR_VIEW);
			}else if(HttpServletResponse.SC_GATEWAY_TIMEOUT == e.getStatusCode()){
				modelAndView.setViewName(TIME_OUT_VIEW);
			}else if(HttpServletResponse.SC_BAD_REQUEST == e.getStatusCode()){
				modelAndView.setViewName(INVALID_REQUEST_ERROR_VIEW);
			}else if(HttpServletResponse.SC_UNAUTHORIZED == e.getStatusCode()){
				modelAndView.setViewName(UNAUTHORIZED_ERROR_VIEW);
			}else if(HttpServletResponse.SC_FORBIDDEN == e.getStatusCode()){
				modelAndView.setViewName(FORBIDDEN_ERROR_VIEW);
			}else if(HttpServletResponse.SC_NOT_FOUND == e.getStatusCode()){
				modelAndView.setViewName(NOT_FOUND_ERROR_VIEW);
			}
			modelAndView.addObject("message", e.getMessage());
			modelAndView.addObject("url", request.getRequestURL().toString());
			return modelAndView;
		}
	}

	/**
	 * 500通用异常处理
	 */
	@ExceptionHandler(value = Exception.class)
	public ModelAndView defaultErrorHandler(HttpServletRequest request, HttpServletResponse response, Exception e) throws Exception {
		return this.businessErrorHandler(request, response, new BusinessException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e));
	}

	/**
	 * 400参数异常处理
	 */
	@ExceptionHandler(value = FeignException.class)
	public ModelAndView feignExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) throws Exception {
		return this.businessErrorHandler(request, response, new BusinessException(HttpServletResponse.SC_NOT_FOUND, e.getMessage(), e));
	}

	/**
	 * 504请求超时异常处理
	 */
	@ExceptionHandler(value = RetryableException.class)
	public ModelAndView retryableExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) throws Exception {
		return this.businessErrorHandler(request, response, new BusinessException(HttpServletResponse.SC_GATEWAY_TIMEOUT, e.getMessage(), e));
	}

	/**
	 * 403请求超时异常处理
	 */
	@ExceptionHandler(value = AccessDeniedException.class)
	public ModelAndView accessDeniedExceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e) throws Exception {
		return this.businessErrorHandler(request, response, new BusinessException(HttpServletResponse.SC_FORBIDDEN, e.getMessage(), e));
	}

	/**
	 * 判断是否ajax提交
	 */
	private boolean isAjax(HttpServletRequest request) {
		return (request.getHeader("accept").contains("application/json") || (request.getHeader("X-Requested-With") != null && request.getHeader("X-Requested-With").contains("XMLHttpRequest")));
	}
}
